﻿using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace IOP.Pulsar.Abstractions
{
    /// <summary>
    /// 默认管线构建者
    /// </summary>
    public class ProductLineBuilder<TContext> : IProductLineBuilder<TContext>
        where TContext : class
    {
        /// <summary>
        /// 中间件列表
        /// </summary>
        private readonly IList<Func<ProductLineDelegate<TContext>, ProductLineDelegate<TContext>>> _Middlewares =
            new List<Func<ProductLineDelegate<TContext>, ProductLineDelegate<TContext>>>();

        /// <summary>
        /// 服务
        /// </summary>
        private readonly IServiceProvider _service;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="provider"></param>
        public ProductLineBuilder(IServiceProvider provider)
        {
            _service = provider ?? throw new ArgumentNullException(nameof(IServiceProvider));
        }

        /// <summary>
        /// 构建管道
        /// </summary>
        /// <returns></returns>
        public virtual ProductLineDelegate<TContext> Build()
        {
            ProductLineDelegate<TContext> productline = next =>
            {
                return Task.CompletedTask;
            };
            foreach (var middleware in _Middlewares.Reverse())
            {
                productline = middleware(productline);
            }

            return productline;
        }

        /// <summary>
        /// 添加中间件
        /// </summary>
        /// <param name="middleware"></param>
        /// <returns></returns>
        public virtual IProductLineBuilder<TContext> Use(Func<ProductLineDelegate<TContext>, ProductLineDelegate<TContext>> middleware)
        {
            _Middlewares.Add(middleware);
            return this;
        }

        /// <summary>
        /// 中间件断路函数
        /// </summary>
        /// <param name="endPoint"></param>
        /// <returns></returns>
        public virtual IProductLineBuilder<TContext> Run(ProductLineDelegate<TContext> endPoint)
        {
            endPoint = endPoint ?? throw new ArgumentNullException(nameof(endPoint));
            return Use(next => endPoint);
        }

        /// <summary>
        /// 使用中间件
        /// </summary>
        /// <typeparam name="TMiddleware"></typeparam>
        /// <returns></returns>
        public virtual IProductLineBuilder<TContext> UseMiddleware<TMiddleware>()
            where TMiddleware : class, IProductLineMiddleware<TContext>
        {
            try
            {
                var middleware = ActivatorUtilities.CreateInstance<TMiddleware>(_service);
                return Use(next =>
                {
                    return async context =>
                    {
                        await middleware.InvokeAsync(context, next);
                    };
                });
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        /// <summary>
        /// 清除所有中间件
        /// </summary>
        public void Clear()
        {
            _Middlewares.Clear();
        }
    }
}
